/*
 *    Copyright (c) 2018-2025, boss All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * Neither the name of the boss developer nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 * Author: boss
 */
package com.hopes.bizz.poll.om.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hopes.bizz.common.core.util.CollectionUtils;
import com.hopes.bizz.common.core.util.StringUtils;
import com.hopes.bizz.poll.common.constant.PollFactorConstant;
import com.hopes.bizz.poll.common.constant.enums.OmHisDataTypeEnums;
import com.hopes.bizz.poll.common.constant.enums.PollModDictEnum;
import com.hopes.bizz.poll.factor.entity.PollDisplayFactorEntity;
import com.hopes.bizz.poll.factor.service.PollDisplayFactorService;
import com.hopes.bizz.poll.gis.dto.GisMonitorHisDTO;
import com.hopes.bizz.poll.gis.vo.GisAir;
import com.hopes.bizz.poll.gis.vo.GisWater;
import com.hopes.bizz.poll.monitor.entity.PollMonitorFactorEntity;
import com.hopes.bizz.poll.monitor.entity.PollMonitorSiteEntity;
import com.hopes.bizz.poll.monitor.service.PollMonitorFactorService;
import com.hopes.bizz.poll.monitor.service.PollMonitorSiteService;
import com.hopes.bizz.poll.monitor.service.PollMonitorTypeService;
import com.hopes.bizz.poll.om.dto.PollDataAlterDto;
import com.hopes.bizz.poll.om.dto.PollRtDataDTO;
import com.hopes.bizz.poll.om.entity.BaseOmDataEntity;
import com.hopes.bizz.poll.om.entity.PollRtDataHisEntity;
import com.hopes.bizz.poll.om.mapper.PollDataHisMapper;
import com.hopes.bizz.poll.om.mapper.PollRtDataHisMapper;
import com.hopes.bizz.poll.om.service.PollDayService;
import com.hopes.bizz.poll.om.service.PollHourService;
import com.hopes.bizz.poll.om.service.PollMinService;
import com.hopes.bizz.poll.om.service.PollRtDataHisService;
import com.hopes.bizz.poll.om.vo.PollRtDataVO;
import com.hopes.bizz.poll.pollaqi.entity.Aqi;
import com.hopes.bizz.poll.pollaqi.util.AqiUtil;
import com.hopes.bizz.poll.pollaqi.util.WqiUtil;
import com.hopes.boss.admin.api.resolver.DictResolver;
import com.hopes.boss.common.core.exception.BizException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

import static com.hopes.bizz.poll.common.constant.OmConstant.*;

/**
 * 实时监控数据历史
 *
 * @author daijie
 * @date 2023-05-23 15:29:53
 */
@Service("pollRtDataHis")
public class PollRtDataHisServiceImpl extends ServiceImpl<PollRtDataHisMapper, PollRtDataHisEntity> implements PollRtDataHisService {

    @Autowired
    private PollMonitorSiteService pollMonitorSiteService;
    @Autowired
    private PollDisplayFactorService pollDisplayFactorService;
    @Autowired
    private PollMonitorFactorService pollMonitorFactorService;
    @Autowired
    @Lazy
    private PollMinService pollMinService;
    @Autowired
    @Lazy
    private PollHourService pollHourService;
    @Autowired
    @Lazy
    private PollDayService pollDayService;
    @Autowired
    private PollMonitorTypeService pollMonitorTypeService;
    @Resource
    private PollDataHisMapper pollDataHisMapper;

    @Override
    public void deleteByMonitorSiteIdAndDataTime(BaseOmDataEntity omDataEntity) {
        this.baseMapper.deleteByMonitorSiteIdAndDataTime(omDataEntity);
    }

    @Override
    public List<PollRtDataHisEntity> queryByTimeAndMonitorList(PollRtDataDTO pollRtDataDTO) {
        return baseMapper.queryByTimeAndMonitorList(pollRtDataDTO);
    }

    @Override
    public List<PollRtDataVO> queryByTimeAndMonitor(PollRtDataDTO pollRtDataDTO) {
        return baseMapper.queryByTimeAndMonitor(pollRtDataDTO);
    }

    @Override
    public Page<PollRtDataVO> selectPageByMonitorSiteIdAndDataType(Page<PollRtDataVO> page, PollRtDataDTO pollRtDataDTO) {
        return baseMapper.selectPageByMonitorSiteIdAndDataType(page, pollRtDataDTO);
    }

    @Override
    public void handleCalculateAQITask(JSONObject dataO, JSONObject sumO, String valKey) {
        for (String factorKey : dataO.keySet()) {
            JSONObject factorO = new JSONObject();

            if (sumO.containsKey(factorKey)) {
                factorO = sumO.getJSONObject(factorKey);
            } else {
                factorO.put("key", factorKey);
                factorO.put("max", Double.MIN_VALUE);
                factorO.put("min", Double.MAX_VALUE);
                factorO.put("val", 0);
                factorO.put("factorNum", 0);
            }

            JSONObject factorValO = dataO.getJSONObject(factorKey);

            if (factorValO.containsKey(valKey)) {
                // 因子个数+1
                factorO.put("factorNum", factorO.getIntValue("factorNum") + 1);

                double factorValRtd = factorValO.getDoubleValue(valKey);
                // 均值处理
                double avg = factorO.getDoubleValue("val");
                avg = avg + factorValRtd;
                factorO.put("val", avg);

                // 最大值处理
                double factorValMax = factorValO.getDoubleValue("max");
                if (factorValMax > factorO.getDoubleValue("max")) {
                    factorO.put("max", factorValMax);
                }

                // 最小值处理
                double factorValMin = factorValO.getDoubleValue("min");
                if (factorValMin < factorO.getDoubleValue("min")) {
                    factorO.put("min", factorValMin);
                }
            }

            sumO.put(factorKey, factorO);
        }
    }


    @Override
    public void handleCalculateWQITask(JSONObject dataO, JSONObject sumO, String valKey) {
        for (String factorKey : dataO.keySet()) {
            JSONObject factorO = new JSONObject();

            if (sumO.containsKey(factorKey)) {
                factorO = sumO.getJSONObject(factorKey);
            } else {
                factorO.put("key", factorKey);
                factorO.put("max", Double.MIN_VALUE);
                factorO.put("min", Double.MAX_VALUE);
                factorO.put("val", 0);
                factorO.put("factorNum", 0);
            }

            JSONObject factorValO = dataO.getJSONObject(factorKey);

            if (factorValO.containsKey(valKey)) {
                // 因子个数+1
                factorO.put("factorNum", factorO.getIntValue("factorNum") + 1);

                double factorValRtd = factorValO.getDoubleValue(valKey);
                // 均值处理
                double avg = factorO.getDoubleValue("val");
                avg = avg + factorValRtd;
                factorO.put("val", avg);

                // 最大值处理
                double factorValMax = factorValO.getDoubleValue("max");
                if (factorValMax > factorO.getDoubleValue("max")) {
                    factorO.put("max", factorValMax);
                }

                // 最小值处理
                double factorValMin = factorValO.getDoubleValue("min");
                if (factorValMin < factorO.getDoubleValue("min")) {
                    factorO.put("min", factorValMin);
                }
            }

            sumO.put(factorKey, factorO);
        }
    }


    @Override
    public Aqi calculateAQI(JSONObject sumO) {
        return AqiUtil.CountAqi(this.getAqiFactorValue(sumO, PollFactorConstant.PM2_5), this.getAqiFactorValue(sumO, PollFactorConstant.PM10), this.getAqiFactorValue(sumO, PollFactorConstant.CO), this.getAqiFactorValue(sumO, PollFactorConstant.NO2), this.getAqiFactorValue(sumO, PollFactorConstant.O3), this.getAqiFactorValue(sumO, PollFactorConstant.SO2));
    }

    @Override
    public Aqi calculateWQI(JSONObject sumO) {
        return WqiUtil.CountWqi(this.getAqiFactorValue(sumO, PollFactorConstant.PH), this.getAqiFactorValue(sumO, PollFactorConstant.TONE),
                this.getAqiFactorValue(sumO, PollFactorConstant.COD), this.getAqiFactorValue(sumO, PollFactorConstant.CR),
                this.getAqiFactorValue(sumO, PollFactorConstant.PB), this.getAqiFactorValue(sumO, PollFactorConstant.NI),
                this.getAqiFactorValue(sumO, PollFactorConstant.CU), this.getAqiFactorValue(sumO, PollFactorConstant.N),
                this.getAqiFactorValue(sumO, PollFactorConstant.NH), this.getAqiFactorValue(sumO, PollFactorConstant.TP),
                this.getAqiFactorValue(sumO, PollFactorConstant.CL), this.getAqiFactorValue(sumO, PollFactorConstant.FW));
    }

    private double getAqiFactorValue(JSONObject sumO, String code) {
        if (sumO.containsKey(code)) {
            return sumO.getJSONObject(code).getDoubleValue("val");
        }
        return 0;
    }

    @Override
    public Page<PollRtDataVO> queryByMonitorAndTimeType(Page<PollRtDataVO> page, PollRtDataDTO pollRtDataDTO) {
        // 查询站点
        LambdaQueryWrapper<PollMonitorSiteEntity> monitorWrapper = new LambdaQueryWrapper<>();
        // 站点类型
        monitorWrapper.eq(ObjectUtil.isNotEmpty(pollRtDataDTO.getMonitorType()), PollMonitorSiteEntity::getMonitorType, pollRtDataDTO.getMonitorType());
        // 企业
        monitorWrapper.eq(ObjectUtil.isNotEmpty(pollRtDataDTO.getOrgId()), PollMonitorSiteEntity::getOrgId, pollRtDataDTO.getOrgId());
        // 站点id
        monitorWrapper.eq(ObjectUtil.isNotEmpty(pollRtDataDTO.getMonitorSiteId()), PollMonitorSiteEntity::getId, pollRtDataDTO.getMonitorSiteId());
        // 所属乡镇
        monitorWrapper.eq(ObjectUtil.isNotEmpty(pollRtDataDTO.getTownId()), PollMonitorSiteEntity::getTownId, pollRtDataDTO.getTownId());
        // 站点大类
        if (Objects.nonNull(pollRtDataDTO.getMonitorTypeMain())) {
            List<Integer> monitorTypeByMain = pollMonitorTypeService.getMonitorTypeByMain(pollRtDataDTO.getMonitorTypeMain());
            monitorWrapper.in(PollMonitorSiteEntity::getMonitorType, monitorTypeByMain);
        }

        List<Long> idList = pollMonitorSiteService.list(monitorWrapper).stream().map(PollMonitorSiteEntity::getId).collect(Collectors.toList());
        // 根据站点类型和时间类型查询数据
        pollRtDataDTO.setIdList(idList);
        if (CollectionUtils.isEmpty(idList)) {
            return new Page<>();
        }
        // 不同类型的数据查询不同的表
        Page<PollRtDataVO> pollRtDataPage = getPollRtDataVOPage(page, pollRtDataDTO);

        // 只显示要展示的数据
        for (PollRtDataVO pollRtDataVO : pollRtDataPage.getRecords()) {
            JSONObject jsonObject = buildDisplayData(pollRtDataDTO.getMonitorTypeMain(), pollRtDataDTO.getMonitorType(), pollRtDataVO.getDataJson(), pollRtDataVO.getMonitorSiteId());
            pollRtDataVO.setMonitorType(DictResolver.getItemByValue(PollModDictEnum.monitor_site, String.valueOf(pollRtDataVO.getMonitorSiteId())).getExt2());
            pollRtDataVO.setDataJson(jsonObject);
        }
        return pollRtDataPage;
    }

    // 根据不同的时间类型查询不同的历史表数据
    private Page<PollRtDataVO> getPollRtDataVOPage(Page<PollRtDataVO> page, PollRtDataDTO pollRtDataDTO) {
        Page<PollRtDataVO> pollRtDataPage = new Page<>();
        if (DATA_TYPE_RT.equals(pollRtDataDTO.getDataType())) {
            // 实时
            pollRtDataPage = this.selectPageByMonitorSiteIdAndDataType(page, pollRtDataDTO);
        } else if (DATA_TYPE_MIN.equals(pollRtDataDTO.getDataType())) {
            // 分钟
            pollRtDataPage = pollMinService.selectPageByMonitorSiteIdAndDataType(page, pollRtDataDTO);
        } else if (DATA_TYPE_HOUR.equals(pollRtDataDTO.getDataType())) {
            // 小时
            pollRtDataPage = pollHourService.selectPageByMonitorSiteIdAndDataType(page, pollRtDataDTO);
        } else if (DATA_TYPE_DAY.equals(pollRtDataDTO.getDataType())) {
            // 日
            pollRtDataPage = pollDayService.selectPageByMonitorSiteIdAndDataType(page, pollRtDataDTO);
        }
        return pollRtDataPage;
    }

    // 构建要展示的数据
    private JSONObject buildDisplayData(Integer monitorTypeMain, Integer monitorType, JSONObject data, Long monitorSiteId) {
        if (data == null) {
            return new JSONObject();
        }
        LambdaQueryWrapper<PollDisplayFactorEntity> wrapper = new LambdaQueryWrapper<>();
        String ids = null;
        if (StringUtils.isNotBlank(monitorTypeMain)) {
            List<Integer> monitorTypeList = pollMonitorTypeService.getMonitorTypeByMain(monitorTypeMain);
            wrapper.in(PollDisplayFactorEntity::getMonitorType, monitorTypeList);
            ids = pollDisplayFactorService.list(wrapper).stream().map(PollDisplayFactorEntity::getFactorIds).collect(Collectors.joining());
        } else if (StringUtils.isNotBlank(monitorType)) {
            wrapper.eq(PollDisplayFactorEntity::getMonitorType, monitorType);
            ids = pollDisplayFactorService.getOne(wrapper).getFactorIds();
        }
        if (StringUtils.isEmpty(ids)) {
            // 展示因子为空
            return new JSONObject();
        }
        // 获取展示因子id
        LambdaQueryWrapper<PollMonitorFactorEntity> queryWrapper = new LambdaQueryWrapper<>();
        List<String> factorIds = CollectionUtils.arrayToList(ids.split(","));
        queryWrapper.in(CollectionUtils.isNotEmpty(factorIds), PollMonitorFactorEntity::getFactorId, factorIds);
        queryWrapper.eq(ObjectUtil.isNotEmpty(monitorSiteId), PollMonitorFactorEntity::getMonitorSiteId, monitorSiteId);
        // 查询展示因子详细信息
        List<PollMonitorFactorEntity> pollFactorInfoList = pollMonitorFactorService.list(queryWrapper);
        JSONObject res = new JSONObject();
        for (PollMonitorFactorEntity pollMonitorFactor : pollFactorInfoList) {
            String code = pollMonitorFactor.getFactorCode();
            JSONObject jsonObject = data.getJSONObject(code);
            if (ObjectUtil.isNotNull(jsonObject)) {
                res.put(pollMonitorFactor.getFactorCode(), jsonObject);
            }
        }

        return res;
    }

    @Override
    public void alter(PollDataAlterDto pollDataAlterDto) {
        Integer dataType = pollDataAlterDto.getDataType();
        String table = OmHisDataTypeEnums.getTableByCode(dataType);
        if (StringUtils.isBlank(table)) {
            throw new BizException("修约数据失败,数据类型不匹配");
        }
        JSONObject dataJson = pollDataAlterDto.getDataJson();
        String data = dataJson.toString();
        pollDataHisMapper.alterData(table, pollDataAlterDto.getId(), data);
    }

    @Override
    public List<GisAir> queryGisAirMonitorHis(GisMonitorHisDTO gisMonitorHisDTO) {

        return baseMapper.queryGisAirMonitorHis(gisMonitorHisDTO.getBeginTime(), gisMonitorHisDTO.getEndTime());
    }

    @Override
    public List<GisWater> queryGisWaterMonitorHis(GisMonitorHisDTO gisMonitorHisDTO) {
        return baseMapper.queryGisWaterMonitorHis(gisMonitorHisDTO);
    }
}
